package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Name  string
	Age   int
	Score float32
}

func test(b interface{}) {
	// b = 100  // 测试过，在test内部修改了a，并不会修改外部的a的值
	// 通过反射获取得到参数的类型
	t := reflect.TypeOf(b) // 传入结构体时返回具体的结构体类型
	fmt.Println(t)
	fmt.Println(b)
	// 通过反射获取得到参数的值
	v := reflect.ValueOf(b)
	k := v.Kind() // 传入结构体时返回struct
	fmt.Println(v)
	fmt.Println(k)

	// 通过反射获取得到参数的值；再转换成interface类型
	iv := v.Interface()
	stu, ok := iv.(Student)
	if ok {
		fmt.Printf("%v %T \n", stu, stu)
	}
}
func (s Student) SetName(name string) {
	s.Name = name
}

func (s Student) Print() {
	fmt.Println("---start---")
	fmt.Println(s)
	fmt.Println("---stop---")
}

func TestStruct(a interface{}) {
	val := reflect.ValueOf(a)
	kd := val.Kind()
	if kd != reflect.Struct {
		fmt.Println("expect struct")
		return
	}
	// 动态获取结构体的字段个数
	num := val.NumField()
	fmt.Printf("struct has %d field\n", num)
	// 动态获取结构体的方法个数,注意如果方法传入的是指针那么是获取不到当前方法个数的
	numOfmethod := val.NumMethod()
	fmt.Printf("struct has %d field\n", numOfmethod)
	// 表示通过反射执行结构体的第一个方法
	var p []reflect.Value
	val.Method(0).Call(p)

}
func main() {
	var a int = 200

	test(a)
	// 在test内部修改了a，并不会修改外部的a的值
	fmt.Println(a)
	b := Student{
		Name:  "test",
		Age:   12,
		Score: 88.5,
	}
	test(b)
	TestStruct(b)
}
